package com.scs.application.core.jackson;

import com.scs.application.core.utils.DateUtils;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Description:
 */
public class CustomDateFormat extends DateFormat {

    private Locale locale;
    private TimeZone timeZone;

    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
            = new ConcurrentHashMap<>(3);

    public CustomDateFormat() {
        this.locale = Locale.getDefault(Locale.Category.FORMAT);
        this.timeZone = TimeZone.getTimeZone("GMT+8:00");

        initializeCalendar(locale);
        initialize(locale);
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return toAppendTo.append(DateUtils.format(date, DateUtils.DEFAULT_PATTER));
    }

    @Override
    public Date parse(String source, ParsePosition pos) {
        return DateUtils.parse(source);
    }

    /**
     * Initialize numberFormat fields
     */
    private void initialize(Locale loc) {

        /* try the cache first */
        numberFormat = cachedNumberFormatData.get(loc);
        if (numberFormat == null) {
            /* cache miss */
            numberFormat = NumberFormat.getIntegerInstance(loc);
            numberFormat.setGroupingUsed(false);

            /* update cache */
            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
        }
        numberFormat = (NumberFormat) numberFormat.clone();

    }

    private void initializeCalendar(Locale loc) {
        if (calendar == null) {
            assert loc != null;
            // The format object must be constructed using the symbols for this zone.
            // However, the calendar should use the current default TimeZone.
            // If this is not contained in the locale zone strings, then the zone
            // will be formatted using generic GMT+/-H:MM nomenclature.
            calendar = Calendar.getInstance(timeZone, loc);
        }
    }

    @Override
    public Object clone() {
        CustomDateFormat other = new CustomDateFormat();
        other.timeZone = (TimeZone) timeZone.clone();
        other.calendar = (Calendar) calendar.clone();
        other.numberFormat = (NumberFormat) numberFormat.clone();
        return other;
    }
}
